home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / GregorianCalendar.java < prev    next >
Text File  |  1998-09-22  |  62KB  |  1,491 lines

  1. /*
  2.  * @(#)GregorianCalendar.java    1.29 98/02/02
  3.  *
  4.  * (C) Copyright Taligent, Inc. 1996-1997 - All Rights Reserved
  5.  * (C) Copyright IBM Corp. 1996-1997 - All Rights Reserved
  6.  *
  7.  * Portions copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
  8.  *
  9.  *   The original version of this source code and documentation is copyrighted
  10.  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  11.  * materials are provided under terms of a License Agreement between Taligent
  12.  * and Sun. This technology is protected by multiple US and International
  13.  * patents. This notice and attribution to Taligent may not be removed.
  14.  *   Taligent is a registered trademark of Taligent, Inc.
  15.  *
  16.  * Permission to use, copy, modify, and distribute this software
  17.  * and its documentation for NON-COMMERCIAL purposes and without
  18.  * fee is hereby granted provided that this copyright notice
  19.  * appears in all copies. Please refer to the file "copyright.html"
  20.  * for further important copyright and licensing information.
  21.  *
  22.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  23.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  24.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  25.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  26.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  27.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  28.  *
  29.  */
  30.  
  31. package java.util;
  32.  
  33. /**
  34.  * <code>GregorianCalendar</code> is a concrete subclass of
  35.  * <a href="java.util.Calendar.html"><code>Calendar</code></a>
  36.  * and provides the standard calendar used by most of the world.
  37.  *
  38.  * <p>
  39.  * The standard (Gregorian) calendar has 2 eras, BC and AD.
  40.  *
  41.  * <p>
  42.  * This implementation handles a single discontinuity, which corresponds
  43.  * by default to the date the Gregorian calendar was instituted (October 15,
  44.  * 1582 in some countries, later in others). This cutover date may be changed
  45.  * by the caller.
  46.  *
  47.  * <p>
  48.  * Prior to the institution of the Gregorian calendar, New Year's Day was
  49.  * March 25. To avoid confusion, this calendar always uses January 1. A manual
  50.  * adjustment may be made if desired for dates that are prior to the Gregorian
  51.  * changeover and which fall between January 1 and March 24.
  52.  *
  53.  * <p>
  54.  * <strong>Example:</strong>
  55.  * <blockquote>
  56.  * <pre>
  57.  * // get the supported ids for GMT-08:00 (Pacific Standard Time)
  58.  * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
  59.  * // if no ids were returned, something is wrong. get out.
  60.  * if (ids.length == 0)
  61.  *     System.exit(0);
  62.  *
  63.  *  // begin output
  64.  * System.out.println("Current Time");
  65.  *
  66.  * // create a Pacific Standard Time time zone
  67.  * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
  68.  *
  69.  * // set up rules for daylight savings time
  70.  * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
  71.  * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
  72.  *
  73.  * // create a GregorianCalendar with the Pacific Daylight time zone
  74.  * // and the current date and time
  75.  * Calendar calendar = new GregorianCalendar(pdt);
  76.  * Date trialTime = new Date();
  77.  * calendar.setTime(trialTime);
  78.  *
  79.  * // print out a bunch of interesting things
  80.  * System.out.println("ERA: " + calendar.get(Calendar.ERA));
  81.  * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
  82.  * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
  83.  * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
  84.  * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
  85.  * System.out.println("DATE: " + calendar.get(Calendar.DATE));
  86.  * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
  87.  * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
  88.  * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
  89.  * System.out.println("DAY_OF_WEEK_IN_MONTH: "
  90.  *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
  91.  * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
  92.  * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
  93.  * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
  94.  * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
  95.  * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
  96.  * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
  97.  * System.out.println("ZONE_OFFSET: "
  98.  *                    + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
  99.  * System.out.println("DST_OFFSET: "
  100.  *                    + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
  101.  
  102.  * System.out.println("Current Time, with hour reset to 3");
  103.  * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
  104.  * calendar.set(Calendar.HOUR, 3);
  105.  * System.out.println("ERA: " + calendar.get(Calendar.ERA));
  106.  * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
  107.  * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
  108.  * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
  109.  * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
  110.  * System.out.println("DATE: " + calendar.get(Calendar.DATE));
  111.  * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
  112.  * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
  113.  * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
  114.  * System.out.println("DAY_OF_WEEK_IN_MONTH: "
  115.  *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
  116.  * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
  117.  * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
  118.  * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
  119.  * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
  120.  * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
  121.  * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
  122.  * System.out.println("ZONE_OFFSET: "
  123.  *        + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
  124.  * System.out.println("DST_OFFSET: "
  125.  *        + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
  126.  * </pre>
  127.  * </blockquote>
  128.  *
  129.  * @see          Calendar
  130.  * @see          TimeZone
  131.  * @version      1.29 02/02/98
  132.  * @author       David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
  133.  */
  134. public class GregorianCalendar extends Calendar {
  135.  
  136.     // Internal notes:
  137.     // This algorithm is based on the one presented on pp. 10-12 of
  138.     // "Numerical Recipes in C", William H. Press, et. al., Cambridge
  139.     // University Press 1988, ISBN 0-521-35465-X.
  140.  
  141.     /**
  142.      * Useful constant for GregorianCalendar.
  143.      */
  144.     public static final int BC = 0;
  145.     /**
  146.      * Useful constant for GregorianCalendar.
  147.      */
  148.     public static final int AD = 1;
  149.  
  150.     // Note that the Julian date used here is not a true Julian date, since
  151.     // it is measured from midnight, not noon.
  152.  
  153.     private static final long julianDayOffset = 2440588;
  154.     private static final int millisPerDay = 24 * 60 * 60 * 1000;
  155.     private static final int NUM_DAYS[]
  156.     = {0,31,59,90,120,151,181,212,243,273,304,334}; // 0-based, for day-in-year
  157.     private static final int LEAP_NUM_DAYS[]
  158.     = {0,31,60,91,121,152,182,213,244,274,305,335}; // 0-based, for day-in-year
  159.     private static final int MONTH_LENGTH[]
  160.     = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
  161.     private static final int LEAP_MONTH_LENGTH[]
  162.     = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
  163.  
  164.     // This is measured from the standard epoch, not in Julian Days.
  165.     // Default is 00:00:00 local time, October 15, 1582.
  166.     private long gregorianCutover = -12219292800000L;
  167.  
  168.     // The onset of the Julian calendar is 45 B.C.  The Julian day
  169.     // number for the start of the year 45 B.C. is 1712653.  We compute
  170.     // the Julian onset as epoch-based millis.  Note that this number is
  171.     // useful for rough comparison purposes only; it's not exact. [LIU]
  172.     private static long JULIAN_ONSET = (1712653 - julianDayOffset) * millisPerDay;
  173.  
  174.     // Useful millisecond constants
  175.     private static final long ONE_SECOND = 1000;
  176.     private static final long ONE_MINUTE = 60*ONE_SECOND;
  177.     private static final long ONE_HOUR   = 60*ONE_MINUTE;
  178.     private static final long ONE_DAY    = 24*ONE_HOUR;
  179.     private static final long ONE_WEEK   = 7*ONE_DAY;
  180.  
  181.     // Proclaim serialization compatiblity with JDK 1.1
  182.     static final long serialVersionUID = -8125100834729963327L;
  183.  
  184.     /**
  185.      * Converts time as milliseconds to Julian date.
  186.      * @param millis the given milliseconds.
  187.      * @return the Julian date number.
  188.      */
  189.     private static final long millisToJulianDay(long millis)
  190.     {
  191.         if (millis >= 0)
  192.             return julianDayOffset + (millis / millisPerDay);
  193.         else
  194.             return julianDayOffset
  195.                 + ((millis - millisPerDay + 1) / millisPerDay);
  196.     }
  197.  
  198.     /**
  199.      * Converts Julian date to time as milliseconds.
  200.      * @param julian the given Julian date number.
  201.      * @return time as milliseconds.
  202.      */
  203.     private static final long julianDayToMillis(long julian)
  204.     {
  205.         return (julian - julianDayOffset) * millisPerDay;
  206.     }
  207.  
  208.     /**
  209.      * Constructs a default GregorianCalendar using the current time
  210.      * in the default time zone with the default locale.
  211.      */
  212.     public GregorianCalendar()
  213.     {
  214.         this(TimeZone.getDefault(), Locale.getDefault());
  215.     }
  216.  
  217.     /**
  218.      * Constructs a GregorianCalendar based on the current time
  219.      * in the given time zone with the default locale.
  220.      * @param zone the given time zone.
  221.      */
  222.     public GregorianCalendar(TimeZone zone)
  223.     {
  224.         this(zone, Locale.getDefault());
  225.     }
  226.  
  227.     /**
  228.      * Constructs a GregorianCalendar based on the current time
  229.      * in the default time zone with the given locale.
  230.      * @param aLocale the given locale.
  231.      */
  232.     public GregorianCalendar(Locale aLocale)
  233.     {
  234.         this(TimeZone.getDefault(), aLocale);
  235.     }
  236.  
  237.     /**
  238.      * Constructs a GregorianCalendar based on the current time
  239.      * in the given time zone with the given locale.
  240.      * @param zone the given time zone.
  241.      * @param aLocale the given locale.
  242.      */
  243.     public GregorianCalendar(TimeZone zone, Locale aLocale)
  244.     {
  245.         super(zone, aLocale);
  246.         setTimeInMillis(System.currentTimeMillis());
  247.     }
  248.  
  249.     /**
  250.      * Constructs a GregorianCalendar with the given date set
  251.      * in the default time zone with the default locale.
  252.      * @param year the value used to set the YEAR time field in the calendar.
  253.      * @param month the value used to set the MONTH time field in the calendar.
  254.      * Month value is 0-based. e.g., 0 for January.
  255.      * @param date the value used to set the DATE time field in the calendar.
  256.      */
  257.     public GregorianCalendar(int year, int month, int date)
  258.     {
  259.         super(TimeZone.getDefault(), Locale.getDefault());
  260.         this.set(ERA, AD);
  261.         this.set(YEAR, year);
  262.         this.set(MONTH, month);
  263.         this.set(DATE, date);
  264.     }
  265.  
  266.     /**
  267.      * Constructs a GregorianCalendar with the given date
  268.      * and time set for the default time zone with the default locale.
  269.      * @param year the value used to set the YEAR time field in the calendar.
  270.      * @param month the value used to set the MONTH time field in the calendar.
  271.      * Month value is 0-based. e.g., 0 for January.
  272.      * @param date the value used to set the DATE time field in the calendar.
  273.      * @param hour the value used to set the HOUR_OF_DAY time field
  274.      * in the calendar.
  275.      * @param minute the value used to set the MINUTE time field
  276.      * in the calendar.
  277.      */
  278.     public GregorianCalendar(int year, int month, int date, int hour,
  279.                              int minute)
  280.     {
  281.         super(TimeZone.getDefault(), Locale.getDefault());
  282.         this.set(ERA, AD);
  283.         this.set(YEAR, year);
  284.         this.set(MONTH, month);
  285.         this.set(DATE, date);
  286.         this.set(HOUR_OF_DAY, hour);
  287.         this.set(MINUTE, minute);
  288.     }
  289.  
  290.     /**
  291.      * Constructs a GregorianCalendar with the given date
  292.      * and time set for the default time zone with the default locale.
  293.      * @param year the value used to set the YEAR time field in the calendar.
  294.      * @param month the value used to set the MONTH time field in the calendar.
  295.      * Month value is 0-based. e.g., 0 for January.
  296.      * @param date the value used to set the DATE time field in the calendar.
  297.      * @param hour the value used to set the HOUR_OF_DAY time field
  298.      * in the calendar.
  299.      * @param minute the value used to set the MINUTE time field
  300.      * in the calendar.
  301.      * @param second the value used to set the SECOND time field
  302.      * in the calendar.
  303.      */
  304.     public GregorianCalendar(int year, int month, int date, int hour,
  305.                              int minute, int second)
  306.     {
  307.         super(TimeZone.getDefault(), Locale.getDefault());
  308.         this.set(ERA, AD);
  309.         this.set(YEAR, year);
  310.         this.set(MONTH, month);
  311.         this.set(DATE, date);
  312.         this.set(HOUR_OF_DAY, hour);
  313.         this.set(MINUTE, minute);
  314.         this.set(SECOND, second);
  315.     }
  316.  
  317.     /**
  318.      * Compares this calendar to the specified object.
  319.      * The result is <code>true</code> if and only if the argument is
  320.      * not <code>null</code> and is a <code>Calendar</code> object that
  321.      * represents the same calendar as this object.
  322.      * @param obj the object to compare with.
  323.      * @return <code>true</code> if the objects are the same;
  324.      * <code>false</code> otherwise.
  325.      */
  326.     public boolean equals(Object obj) {
  327.         // This body moves to Calendar in 1.2
  328.         if (this == obj)
  329.             return true;
  330.         if (!(obj instanceof Calendar))
  331.             return false;
  332.  
  333.         Calendar that = (Calendar)obj;
  334.  
  335.         return getTimeInMillis() == that.getTimeInMillis() &&
  336.             isLenient() == that.isLenient() &&
  337.         getFirstDayOfWeek() == that.getFirstDayOfWeek() &&
  338.             getMinimalDaysInFirstWeek() == that.getMinimalDaysInFirstWeek() &&
  339.             getTimeZone().equals(that.getTimeZone());
  340.     }
  341.  
  342.     /**
  343.      * Compares the time field records.
  344.      * Equivalent to comparing result of conversion to UTC.
  345.      * @param when the Calendar to be compared with this Calendar.
  346.      * @return true if the current time of this Calendar is before
  347.      * the time of Calendar when; false otherwise.
  348.      */
  349.     public boolean before(Object when) {
  350.         // This body moves to Calendar in 1.2
  351.         return when instanceof Calendar &&
  352.             getTimeInMillis() < ((Calendar) when).getTimeInMillis();
  353.     }
  354.  
  355.     /**
  356.      * Compares the time field records.
  357.      * Equivalent to comparing result of conversion to UTC.
  358.      * @param when the Calendar to be compared with this Calendar.
  359.      * @return true if the current time of this Calendar is after
  360.      * the time of Calendar when; false otherwise.
  361.      */
  362.     public boolean after(Object when) {
  363.         // This body moves to Calendar in 1.2
  364.         return when instanceof Calendar &&
  365.             getTimeInMillis() > ((Calendar) when).getTimeInMillis();
  366.     }
  367.  
  368.     /**
  369.      * Sets the GregorianCalendar change date. This is the point when the
  370.      * switch from Julian dates to Gregorian dates occurred. Default is
  371.      * 00:00:00 local time, October 15, 1582. Previous to this time and date
  372.      * will be Julian dates.
  373.      *
  374.      * @param date the given Gregorian cutover date.
  375.      */
  376.     public void setGregorianChange(Date date)
  377.     {
  378.         gregorianCutover = date.getTime();
  379.     }
  380.  
  381.     /**
  382.      * Gets the Gregorian Calendar change date.  This is the point when the
  383.      * switch from Julian dates to Gregorian dates occurred. Default is
  384.      * 00:00:00 local time, October 15, 1582. Previous to
  385.      * this time and date will be Julian dates.
  386.      * @return the Gregorian cutover time for this calendar.
  387.      */
  388.     public final Date getGregorianChange()
  389.     {
  390.         return new Date(gregorianCutover);
  391.     }
  392.  
  393.     private static final int julianDayToDayOfWeek(long julian)
  394.     {
  395.         // If julian is negative, then julian%7 will be negative, so we adjust
  396.         // accordingly.  We add 1 because Julian day 0 is Monday.
  397.         int dayOfWeek = (int)((julian + 1) % 7);
  398.         return dayOfWeek + ((dayOfWeek < 0) ? (7 + SUNDAY) : SUNDAY);
  399.     }
  400.  
  401.     /**
  402.      * Convert the time as milliseconds to the "big" fields.  Millis must be
  403.      * given as local wall millis to get the correct local day.  For example,
  404.      * if it is 11:30 pm Standard, and DST is in effect, the correct DST millis
  405.      * must be passed in to get the right date.
  406.      *
  407.      * Fields that are completed by this method: ERA, YEAR, MONTH, DATE,
  408.      * DAY_OF_WEEK, DAY_OF_YEAR, WEEK_OF_YEAR, WEEK_OF_MONTH,
  409.      * DAY_OF_WEEK_IN_MONTH.
  410.      */
  411.     private final void timeToFields(long theTime)
  412.     {
  413.         int year, month, date, dayOfWeek, dayOfYear, weekCount, era = AD;
  414.  
  415.         //---------------------------------------------------------------------
  416.         // BEGIN modified caldat()
  417.         //---------------------------------------------------------------------
  418.         // The following variable names are somewhat cryptic. Unfortunately,
  419.         // they are from the original program cited above, and no explanation
  420.         // for their meaning is given. Given that the algorithm is cryptic too,
  421.         // perhaps it doesn't matter...
  422.         long ja, jb, jd;
  423.         long jc, je; // changed from int to fix number overflow problem.
  424.  
  425.         long julian = millisToJulianDay(theTime);
  426.  
  427.         if (theTime >= gregorianCutover)
  428.         {
  429.             long jalpha = (long) (((double) (julian - 1867216) - 0.25)
  430.                                   / 36524.25);
  431.             ja = julian + 1 + jalpha - (long) (0.25 * jalpha);
  432.         }
  433.         else
  434.         {
  435.             ja = julian;
  436.         }
  437.         jb = ja + 1524;
  438.         jc = (long) Math.floor(6680.0 + ((double) (jb - 2439870) - 122.1) / 365.25);
  439.         jd = (long) Math.floor(365*jc + (0.25 * jc));
  440.         je = (long) ((jb-jd)/30.6001);
  441.         date = (int) (jb-jd-(long) (30.6001 * je));
  442.         month = (int) je - 1;
  443.         if (month > 12)
  444.             month -= 12;
  445.  
  446.         year = (int) (jc-4715);
  447.         if (month > 2)
  448.             --year;
  449.         if (year <= 0)
  450.         {
  451.             era = BC;
  452.             year = 1-year;
  453.         }
  454.         //---------------------------------------------------------------------
  455.         // END modified caldat()
  456.         //---------------------------------------------------------------------
  457.  
  458.         internalSet(ERA, era);
  459.         internalSet(YEAR, year);
  460.         internalSet(MONTH, month-1); // 0-based
  461.         internalSet(DATE, date);
  462.  
  463.         dayOfWeek = julianDayToDayOfWeek(julian);
  464.         internalSet(DAY_OF_WEEK, dayOfWeek); // CLH, 8-7-96
  465.  
  466.         if (isLeapYear(year))
  467.             dayOfYear = LEAP_NUM_DAYS[month-1] + date; // month: 0-based
  468.         else
  469.             dayOfYear = NUM_DAYS[month-1] + date; // month: 0-based
  470.         internalSet(DAY_OF_YEAR, dayOfYear);
  471.  
  472.         internalSet(WEEK_OF_YEAR, weekNumber(dayOfYear, dayOfWeek));
  473.         internalSet(WEEK_OF_MONTH, weekNumber(date, dayOfWeek));
  474.  
  475.         internalSet(DAY_OF_WEEK_IN_MONTH, (date-1) / 7 + 1);
  476.     }
  477.  
  478.     /**
  479.      * Return the week number of a day, within a period. This may be the week number in
  480.      * a year, or the week number in a month. Usually this will be a value >= 1, but if
  481.      * some initial days of the period are excluded from week 1, because
  482.      * minimalDaysInFirstWeek is > 1, then the week number will be zero for those
  483.      * initial days. Requires the day of week for the given date in order to determine
  484.      * the day of week of the first day of the period.
  485.      *
  486.      * @param dayOfPeriod  Day-of-year or day-of-month. Should be 1 for first day of period.
  487.      * @param day   Day-of-week for given dayOfPeriod. 1-based with 1=Sunday.
  488.      * @return      Week number, one-based, or zero if the day falls in part of the
  489.      *              month before the first week, when there are days before the first
  490.      *              week because the minimum days in the first week is more than one.
  491.      */
  492.     private int weekNumber(int dayOfPeriod, int dayOfWeek)
  493.     {
  494.         // Determine the day of the week of the first day of the period
  495.         // in question (either a year or a month).  Zero represents the
  496.         // first day of the week on this calendar.
  497.         int periodStartDayOfWeek = (dayOfWeek - getFirstDayOfWeek() - dayOfPeriod + 1) % 7;
  498.         if (periodStartDayOfWeek < 0) periodStartDayOfWeek += 7;
  499.  
  500.         // Compute the week number.  Initially, ignore the first week, which
  501.         // may be fractional (or may not be).  We add periodStartDayOfWeek in
  502.         // order to fill out the first week, if it is fractional.
  503.         int weekNo = (dayOfPeriod + periodStartDayOfWeek - 1)/7;
  504.  
  505.         // If the first week is long enough, then count it.  If
  506.         // the minimal days in the first week is one, or if the period start
  507.         // is zero, we always increment weekNo.
  508.         if ((7 - periodStartDayOfWeek) >= getMinimalDaysInFirstWeek()) ++weekNo;
  509.  
  510.         return weekNo;
  511.     }
  512.  
  513.     /**
  514.      * Determines if the given year is a leap year. Returns true if the
  515.      * given year is a leap year.
  516.      * @param year the given year.
  517.      * @return true if the given year is a leap year; false otherwise.
  518.      */
  519.     public boolean isLeapYear(int year)
  520.     {
  521.         // Compute the rough millis for the year.  We only need this number to be
  522.         // good enough to compare it against JULIAN_ONSET.
  523.         long equivalent_millis = (long)((year - 1970) * 365.2422 * millisPerDay);
  524.  
  525.         // No leap years before onset of Julian calendar
  526.         if (equivalent_millis < JULIAN_ONSET)
  527.             return false;
  528.  
  529.         return (equivalent_millis > gregorianCutover) ?
  530.             ((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))) : // Gregorian
  531.             (year%4 == 0); // Julian
  532.     }
  533.  
  534.     /**
  535.      * Overrides Calendar
  536.      * Converts UTC as milliseconds to time field values.
  537.      * The time is <em>not</em>
  538.      * recomputed first; to recompute the time, then the fields, call the
  539.      * <code>complete</code> method.
  540.      * @see Calendar#complete
  541.      */
  542.     protected void computeFields()
  543.     {
  544.         int gmtOffset = getTimeZone().getRawOffset();
  545.         long localMillis = time + gmtOffset;
  546.  
  547.         // Time to fields takes the wall millis (Standard or DST).
  548.         timeToFields(localMillis);
  549.  
  550.         int era = internalGet(ERA);
  551.         int year = internalGet(YEAR);
  552.         int month = internalGet(MONTH);
  553.         int date = internalGet(DATE);
  554.         int dayOfWeek = internalGet(DAY_OF_WEEK);
  555.  
  556.         long days = (long) (localMillis / millisPerDay);
  557.         int millisInDay = (int) (localMillis - (days * millisPerDay));
  558.         if (millisInDay < 0) millisInDay += millisPerDay;
  559.  
  560.         // Call getOffset() to get the TimeZone offset.  The millisInDay value must
  561.         // be standard local millis.
  562.         int dstOffset = getTimeZone().getOffset(era,year,month,date,dayOfWeek,millisInDay) -
  563.             gmtOffset;
  564.  
  565.         // Adjust our millisInDay for DST, if necessary.
  566.         millisInDay += dstOffset;
  567.  
  568.         // If DST has pushed us into the next day, we must call timeToFields() again.
  569.         // This happens in DST between 12:00 am and 1:00 am every day.  The call to
  570.         // timeToFields() will give the wrong day, since the Standard time is in the
  571.         // previous day.
  572.         if (millisInDay >= millisPerDay)
  573.         {
  574.             millisInDay -= millisPerDay;
  575.             localMillis += dstOffset;
  576.             timeToFields(localMillis);
  577.         }
  578.  
  579.         // Fill in all time-related fields based on millisInDay.  Call internalSet()
  580.         // so as not to perturb flags.
  581.         internalSet(MILLISECOND, millisInDay % 1000);
  582.         millisInDay /= 1000;
  583.         internalSet(SECOND, millisInDay % 60);
  584.         millisInDay /= 60;
  585.         internalSet(MINUTE, millisInDay % 60);
  586.         millisInDay /= 60;
  587.         internalSet(HOUR_OF_DAY, millisInDay);
  588.         internalSet(AM_PM, millisInDay / 12);
  589.         internalSet(HOUR, millisInDay % 12);
  590.  
  591.         internalSet(ZONE_OFFSET, gmtOffset);
  592.         internalSet(DST_OFFSET, dstOffset);
  593.  
  594.     // Careful here: We are manually setting the time stamps[] flags to
  595.         // INTERNALLY_SET, so we must be sure that the above code actually does
  596.         // set all these fields.
  597.     for (int i=0; i<FIELD_COUNT; ++i) stamp[i] = INTERNALLY_SET;
  598.  
  599.         // Careful here: We are manually setting the isSet[] flags to true, so we
  600.         // must be sure that the above code actually does set all these fields.
  601.         for (int i=0; i<FIELD_COUNT; ++i) isSet[i] = true; // Remove later
  602.     }
  603.  
  604.     /**
  605.      * Return true if the current time for this Calendar is in Daylignt
  606.      * Savings Time.
  607.      *
  608.      * Note -- MAKE THIS PUBLIC AT THE NEXT API CHANGE.  POSSIBLY DEPRECATE
  609.      * AND REMOVE TimeZone.inDaylightTime().
  610.      */
  611.     boolean inDaylightTime()
  612.     {
  613.         if (!getTimeZone().useDaylightTime()) return false;
  614.         complete(); // Force update of DST_OFFSET field
  615.         return internalGet(DST_OFFSET) != 0;
  616.     }
  617.  
  618.     private final int monthLength(int month, int year)
  619.     {
  620.         return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month];
  621.     }
  622.  
  623.     /**
  624.      * Validates the values of the set time fields.
  625.      */
  626.     private boolean validateFields()
  627.     {
  628.         for (int field = 0; field < FIELD_COUNT; field++)
  629.         {
  630.             // Ignore DATE and DAY_OF_YEAR which are handled below
  631.             if (field != DATE &&
  632.                 field != DAY_OF_YEAR &&
  633.                 isSet(field) &&
  634.                 !boundsCheck(internalGet(field), field))
  635.  
  636.                 return false;
  637.         }
  638.  
  639.         // Values differ in Least-Maximum and Maximum should be handled
  640.         // specially.
  641.         if (isSet(DATE))
  642.         {
  643.             int date = internalGet(DATE);
  644.             return (date >= getMinimum(DATE) &&
  645.                     date <= monthLength(internalGet(MONTH), internalGet(YEAR)));
  646.         }
  647.  
  648.         if (isSet(DAY_OF_YEAR))
  649.         {
  650.             int days = internalGet(DAY_OF_YEAR);
  651.  
  652.             if (isLeapYear(internalGet(YEAR))) {
  653.                 if (days < 1 || days > 366)
  654.                     return false;
  655.             }
  656.             else if (days < 1 || days > 365)
  657.                 return false;
  658.         }
  659.  
  660.         // Handle DAY_OF_WEEK_IN_MONTH, which must not have the value zero.
  661.         // We've checked against minimum and maximum above already.
  662.         if (isSet(DAY_OF_WEEK_IN_MONTH) &&
  663.             0 == internalGet(DAY_OF_WEEK_IN_MONTH)) return false;
  664.  
  665.         return true;
  666.     }
  667.  
  668.     /**
  669.      * Validates the value of the given time field.
  670.      */
  671.     private boolean boundsCheck(int value, int field)
  672.     {
  673.         return value >= getMinimum(field) && value <= getMaximum(field);
  674.     }
  675.  
  676.     /**
  677.      * Return the pseudo-time-stamp for two fields, given their
  678.      * individual pseudo-time-stamps.  If either of the fields
  679.      * is unset, then the aggregate is unset.  Otherwise, the
  680.      * aggregate is the later of the two stamps.
  681.      */
  682.     private final int aggregateStamp(int stamp_a, int stamp_b) {
  683.     return (stamp_a != UNSET && stamp_b != UNSET) ?
  684.         Math.max(stamp_a, stamp_b) : UNSET;
  685.     }
  686.  
  687.     /**
  688.      * Overrides Calendar
  689.      * Converts time field values to UTC as milliseconds.
  690.      * @exception IllegalArgumentException if any fields are invalid.
  691.      */
  692.     protected void computeTime()
  693.     {
  694.         if (!isLenient() && !validateFields())
  695.             throw new IllegalArgumentException();
  696.  
  697.         // This function takes advantage of the fact that unset fields in
  698.         // the time field list have a value of zero.
  699.         long millis = 0;
  700.  
  701.         int era;
  702.         if (stamp[ERA] != UNSET)
  703.             era = internalGet(ERA);
  704.         else
  705.             era = AD;
  706.  
  707.         if (era < BC || era > AD)
  708.             throw new IllegalArgumentException();
  709.  
  710.         // The year defaults to the epoch start.
  711.         int year = (stamp[YEAR] != UNSET) ? internalGet(YEAR) : 1970;
  712.         int month = 0, date = 0;
  713.  
  714.         if (era == BC)
  715.             year = 1 - year;
  716.  
  717.         long julian = 0;
  718.  
  719.     // Find the most recent set of fields specifying the day within
  720.     // the year.  These may be any of the following combinations:
  721.     //  MONTH* + DAY_OF_MONTH*
  722.     //  MONTH* + WEEK_OF_MONTH* + DAY_OF_WEEK
  723.     //  MONTH* + DAY_OF_WEEK_IN_MONTH* + DAY_OF_WEEK
  724.     //  DAY_OF_YEAR*
  725.     //  DAY_OF_WEEK + WEEK_OF_YEAR*
  726.     // We look for the most recent of the fields marked thus*.  If other
  727.     // fields are missing, we use their default values, which are those of
  728.     // the epoch start, or in the case of DAY_OF_WEEK, the first day in
  729.     // the week.
  730.     int monthStamp = stamp[MONTH];
  731.     int domStamp = stamp[DAY_OF_MONTH];
  732.     int womStamp = stamp[WEEK_OF_MONTH];
  733.     int dowimStamp = stamp[DAY_OF_WEEK_IN_MONTH];
  734.     int doyStamp = stamp[DAY_OF_YEAR];
  735.     int woyStamp = stamp[WEEK_OF_YEAR];
  736.  
  737.     int bestStamp = (monthStamp > domStamp) ? monthStamp : domStamp;
  738.     if (womStamp > bestStamp) bestStamp = womStamp;
  739.     if (dowimStamp > bestStamp) bestStamp = dowimStamp;
  740.     if (doyStamp > bestStamp) bestStamp = doyStamp;
  741.     if (woyStamp > bestStamp) bestStamp = woyStamp;
  742.  
  743.     if (bestStamp != UNSET &&
  744.         (bestStamp == monthStamp ||
  745.          bestStamp == domStamp ||
  746.          bestStamp == womStamp ||
  747.          bestStamp == dowimStamp)) {
  748.  
  749.             // We have the month specified. Make it 1-based for the algorithm.
  750.             month = (monthStamp != UNSET ? internalGet(MONTH) : JANUARY) + 1;
  751.             // normalize month
  752.             if (month < 1) {
  753.                 year += month / 12 - 1;
  754.                 month = 12 + month % 12;
  755.             } else if (month > 12) {
  756.                 year += month / 12;
  757.                 month = month % 12;
  758.             }
  759.  
  760.             if (month > 2)
  761.                 ++month;
  762.             else
  763.             {
  764.                 --year;
  765.                 month += 13;
  766.             }
  767.             julian = (long) (Math.floor(365.25*year)
  768.                      + Math.floor(30.6001*month) + 1720995);
  769.  
  770.             if (bestStamp == domStamp ||
  771.         bestStamp == monthStamp) {
  772.  
  773.         date = (domStamp != UNSET) ? internalGet(DAY_OF_MONTH) : 1;
  774.         }
  775.         else { // assert(bestStamp == womStamp || bestStamp == dowimStamp)
  776.                 // Compute from day of week plus week number or from the day of
  777.                 // week plus the day of week in month.  The computations are
  778.                 // almost identical.
  779.  
  780.                 // The first thing we have to do is do the Gregorian adjustment,
  781.                 // if necessary.  We figure out the adjusted value 'j' and use
  782.                 // that.  We redo this later when we get the real final number.
  783.                 // This double computation provides the best accuracy around the
  784.                 // Gregorian cutover.
  785.                 long j = julian;
  786.                 if (julianDayToMillis(julian) >= gregorianCutover)
  787.                 {
  788.                     long adjust = (long) (0.01 * year);
  789.                     j += 2 - adjust + (long) (0.25*adjust);
  790.                 }
  791.  
  792.                 // Find the day of the week for the first of this month.  This
  793.                 // is zero-based, with 0 being the locale-specific first day of
  794.                 // the week.  Add 1 to get the 1st day of month.  Subtract
  795.                 // getFirstDayOfWeek() to make 0-based.
  796.                 int fdm = julianDayToDayOfWeek(j + 1) - getFirstDayOfWeek();
  797.                 if (fdm < 0) fdm += 7;
  798.  
  799.                 // Find the start of the first week.  This will be a date from
  800.                 // 1..-6.  It represents the locale-specific first day of the
  801.                 // week of the first day of the month, ignoring minimal days in
  802.                 // first week.
  803.         date = 1 - fdm + ((stamp[DAY_OF_WEEK] != UNSET) ?
  804.                   (internalGet(DAY_OF_WEEK) - getFirstDayOfWeek()) : 0);
  805.  
  806.                 if (bestStamp == womStamp)
  807.                 {
  808.                     // Adjust for minimal days in first week.
  809.                     if ((7 - fdm) < getMinimalDaysInFirstWeek()) date += 7;
  810.  
  811.                     // Now adjust for the week number.
  812.                     date += 7 * (internalGet(WEEK_OF_MONTH) - 1);
  813.                 }
  814.                 else // assert(bestStamp == dowimStamp)
  815.                 {
  816.                     // Adjust into the month, if needed.
  817.                     if (date < 1) date += 7;
  818.  
  819.                     // We are basing this on the day-of-week-in-month.  The only
  820.                     // trickiness occurs if the day-of-week-in-month is
  821.                     // negative.
  822.                     int dim = internalGet(DAY_OF_WEEK_IN_MONTH);
  823.                     if (dim >= 0) date += 7*(dim - 1);
  824.                     else
  825.                     {
  826.                         // Move date to the last of this day-of-week in this
  827.                         // month, then back up as needed.  If dim==-1, we don't
  828.                         // back up at all.  If dim==-2, we back up once, etc.
  829.                         // Don't back up past the first of the given day-of-week
  830.                         // in this month.  Note that we handle -2, -3,
  831.                         // etc. correctly, even though values < -1 are
  832.                         // technically disallowed.
  833.                         date += ((monthLength(internalGet(MONTH), year) - date) / 7 + dim + 1) * 7;
  834.                     }
  835.                 }
  836.             }
  837.             julian += date;
  838.     }
  839.     else {
  840.         // assert(bestStamp == doyStamp || bestStamp == woyStamp ||
  841.         // bestStamp == UNSET).  In the last case we should use January 1.
  842.  
  843.             // No month, start with January 0 (day before Jan 1), then adjust.
  844.             --year;
  845.             julian = (long) (Math.floor(365.25*year) + 428 + 1720995);
  846.  
  847.         if (bestStamp == UNSET) {
  848.         ++julian;
  849.         }
  850.             else if (bestStamp == doyStamp) {
  851.                 julian += internalGet(DAY_OF_YEAR);
  852.         }
  853.         else if (bestStamp == woyStamp) {
  854.                 // Compute from day of week plus week of year
  855.  
  856.                 // The first thing we have to do is do the Gregorian adjustment,
  857.                 // if necessary.  We figure out the adjusted value 'j' and use
  858.                 // that.  We redo this later when we get the real final number.
  859.                 // This double computation provides the best accuracy around the
  860.                 // Gregorian cutover.
  861.                 long j = julian;
  862.                 if (julianDayToMillis(julian) >= gregorianCutover)
  863.                 {
  864.                     long adjust = (long) (0.01 * year);
  865.                     j += 2 - adjust + (long) (0.25*adjust);
  866.                 }
  867.  
  868.                 // Find the day of the week for the first of this year.  This
  869.                 // is zero-based, with 0 being the locale-specific first day of
  870.                 // the week.  Add 1 to get the 1st day of month.  Subtract
  871.                 // getFirstDayOfWeek() to make 0-based.
  872.                 int fdy = julianDayToDayOfWeek(j + 1) - getFirstDayOfWeek();
  873.                 if (fdy < 0) fdy += 7;
  874.  
  875.                 // Find the start of the first week.  This may be a valid date
  876.                 // from 1..7, or a date before the first, from 0..-6.  It
  877.                 // represents the locale-specific first day of the week
  878.                 // of the first day of the year.
  879.  
  880.                 // First ignore the minimal days in first week.
  881.         date = 1 - fdy + ((stamp[DAY_OF_WEEK] != UNSET) ?
  882.                   (internalGet(DAY_OF_WEEK) - getFirstDayOfWeek()) : 0);
  883.  
  884.                 // Adjust for minimal days in first week.
  885.                 if ((7 - fdy) < getMinimalDaysInFirstWeek()) date += 7;
  886.  
  887.                 // Now adjust for the week number.
  888.                 date += 7 * (internalGet(WEEK_OF_YEAR) - 1);
  889.  
  890.                 julian += date;
  891.             }
  892.     }
  893.  
  894.     // Now adjust for Gregorian if necessary. Note that dates that fall in
  895.     // the "gap" between the Julian and Gregorian calendars will be treated
  896.     // as Gregorian. Strictly speaking, they're illegal.
  897.     millis = julianDayToMillis(julian);
  898.     if (millis >= gregorianCutover)
  899.         {
  900.             long adjust = (long) (0.01 * year);
  901.             julian += 2 - adjust + (long) (0.25*adjust);
  902.             millis = julianDayToMillis(julian);
  903.         }
  904.  
  905.         // Now we can do the time portion of the conversion.
  906.  
  907.         int millisInDay = 0;
  908.  
  909.     // Find the best set of fields specifying the time of day.  There
  910.     // are only two possibilities here; the HOUR_OF_DAY or the
  911.     // AM_PM and the HOUR.
  912.     int hourOfDayStamp = stamp[HOUR_OF_DAY];
  913.     int hourStamp = stamp[HOUR];
  914.     bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
  915.  
  916.         // Hours
  917.     if (bestStamp != UNSET) {
  918.         if (bestStamp == hourOfDayStamp)
  919.         // Don't normalize here; let overflow bump into the next period.
  920.         // This is consistent with how we handle other fields.
  921.         millisInDay += internalGet(HOUR_OF_DAY);
  922.  
  923.         else {
  924.         // Don't normalize here; let overflow bump into the next period.
  925.         // This is consistent with how we handle other fields.
  926.         millisInDay += internalGet(HOUR);
  927.  
  928.         millisInDay += 12 * internalGet(AM_PM); // Default works for unset AM_PM
  929.         }
  930.     }
  931.  
  932.         // Minutes. We use the fact that unset == 0
  933.         millisInDay *= 60;
  934.         millisInDay += internalGet(MINUTE);
  935.  
  936.         // Seconds. unset == 0
  937.         millisInDay *= 60;
  938.         millisInDay += internalGet(SECOND);
  939.  
  940.         // Milliseconds. unset == 0
  941.         millisInDay *= 1000;
  942.         millisInDay += internalGet(MILLISECOND);
  943.  
  944.         // Compute the time zone offset and DST offset.  There are two potential
  945.         // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
  946.         // for discussion purposes here.
  947.         // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
  948.         //    can be in standard or in DST depending.  However, 2:00 am is an invalid
  949.         //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
  950.         //    We assume standard time.
  951.         // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
  952.         //    can be in standard or DST.  Both are valid representations (the rep
  953.         //    jumps from 1:59:59 DST to 1:00:00 Std).
  954.         //    Again, we assume standard time.
  955.         // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
  956.         // or DST_OFFSET fields; then we use those fields.
  957.         TimeZone zone = getTimeZone();
  958.         int zoneOffset = (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP)
  959.         /*isSet(ZONE_OFFSET) && userSetZoneOffset*/ ?
  960.             internalGet(ZONE_OFFSET) : zone.getRawOffset();
  961.  
  962.         // Now add date and millisInDay together, to make millis contain local wall
  963.         // millis, with no zone or DST adjustments
  964.         millis += millisInDay;
  965.  
  966.         int dstOffset = 0;
  967.         if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP
  968.         /*isSet(DST_OFFSET) && userSetDSTOffset*/) dstOffset = internalGet(DST_OFFSET);
  969.         else
  970.         {
  971.             // We need to have the month, the day, and the day of the week.
  972.             // Calling timeToFields will compute the MONTH and DATE fields.
  973.             if (stamp[MONTH] == UNSET || stamp[DATE] == UNSET
  974.         /*!isSet(MONTH) || !isSet(DATE)*/)
  975.                 timeToFields(millis); // Right - use wall time here
  976.  
  977.             // It's tempting to try to use DAY_OF_WEEK here, if it
  978.             // is set, but we CAN'T.  Even if it's set, it might have
  979.             // been set wrong by the user.  We should rely only on
  980.             // the Julian day number, which has been computed correctly
  981.             // using the disambiguation algorithm above. [LIU]
  982.             dstOffset = zone.getOffset(era,
  983.                                        internalGet(YEAR),
  984.                                        internalGet(MONTH),
  985.                                        internalGet(DATE),
  986.                                        julianDayToDayOfWeek(julian),
  987.                                        millisInDay) -
  988.                 zoneOffset;
  989.             // Note: Because we pass in wall millisInDay, rather than
  990.             // standard millisInDay, we interpret "1:00 am" on the day
  991.             // of cessation of DST as "1:00 am Std" (assuming the time
  992.             // of cessation is 2:00 am).
  993.         }
  994.  
  995.         // Store our final computed GMT time, with timezone adjustments.
  996.         time = millis - zoneOffset - dstOffset;
  997.     }
  998.  
  999.     /**
  1000.      * Override hashCode.
  1001.      * Generates the hash code for the GregorianCalendar object
  1002.      */
  1003.     public synchronized int hashCode()
  1004.     {
  1005.         return getFirstDayOfWeek() ^ getMinimalDaysInFirstWeek();
  1006.     }
  1007.  
  1008.     /**
  1009.      * Overrides Calendar
  1010.      * Date Arithmetic function.
  1011.      * Adds the specified (signed) amount of time to the given time field,
  1012.      * based on the calendar's rules.
  1013.      * @param field the time field.
  1014.      * @param amount the amount of date or time to be added to the field.
  1015.      * @exception IllegalArgumentException if an unknown field is given.
  1016.      */
  1017.     public void add(int field, int amount)
  1018.     {
  1019.         if (amount == 0) return;   // Do nothing!
  1020.         complete();
  1021.  
  1022.         if (field == YEAR)
  1023.         {
  1024.             int year = this.internalGet(YEAR);
  1025.             if (this.internalGet(ERA) == AD)
  1026.             {
  1027.                 year += amount;
  1028.                 if (year > 0)
  1029.                     this.set(YEAR, year);
  1030.                 else // year <= 0
  1031.                 {
  1032.                     this.set(YEAR, 1 - year);
  1033.                     // if year == 0, you get 1 BC
  1034.                     this.set(ERA, BC);
  1035.                 }
  1036.             }
  1037.             else // era == BC
  1038.             {
  1039.                 year -= amount;
  1040.                 if (year > 0)
  1041.                     this.set(YEAR, year);
  1042.                 else // year <= 0
  1043.                 {
  1044.                     this.set(YEAR, 1 - year);
  1045.                     // if year == 0, you get 1 AD
  1046.                     this.set(ERA, AD);
  1047.                 }
  1048.             }
  1049.         }
  1050.         else if (field == MONTH)
  1051.         {
  1052.             int month = this.internalGet(MONTH) + amount;
  1053.             if (month >= 0)
  1054.             {
  1055.                 add(YEAR, (int) (month / 12));
  1056.                 set(MONTH, (int) (month % 12));
  1057.             }
  1058.             else // month < 0
  1059.             {
  1060.                 add(YEAR, (int) ((month + 1) / 12) - 1);
  1061.                 month %= 12;
  1062.                 if (month < 0) month += 12;
  1063.                 set(MONTH, JANUARY + month);
  1064.             }
  1065.         int monthLen = monthLength(internalGet(MONTH), internalGet(YEAR));
  1066.         int dom = internalGet(DAY_OF_MONTH);
  1067.         if (dom > monthLen) set(DAY_OF_MONTH, monthLen);
  1068.         }
  1069.         else if (field == ERA)
  1070.         {
  1071.             int era = internalGet(ERA) + amount;
  1072.             if (era < 0) era = 0;
  1073.             if (era > 1) era = 1;
  1074.             set(ERA, era);
  1075.         }
  1076.         else
  1077.         {
  1078.             // We handle most fields here.  The algorithm is to add a computed amount
  1079.             // of millis to the current millis.  The only wrinkle is with DST -- if
  1080.             // the result of the add operation is to move from DST to Standard, or vice
  1081.             // versa, we need to adjust by an hour forward or back, respectively.
  1082.             // Otherwise you get weird effects in which the hour seems to shift when
  1083.             // you add to the DAY_OF_MONTH field, for instance.
  1084.  
  1085.             // Save the current DST state.
  1086.             long dst = internalGet(DST_OFFSET);
  1087.  
  1088.             long delta = amount;
  1089.             switch (field)
  1090.             {
  1091.             case WEEK_OF_YEAR:
  1092.             case WEEK_OF_MONTH:
  1093.             case DAY_OF_WEEK_IN_MONTH:
  1094.                 delta *= 7 * 24 * 60 * 60 * 1000; // 7 days
  1095.                 break;
  1096.  
  1097.             case AM_PM:
  1098.                 delta *= 12 * 60 * 60 * 1000; // 12 hrs
  1099.                 break;
  1100.  
  1101.             case DATE: // synonym of DAY_OF_MONTH
  1102.             case DAY_OF_YEAR:
  1103.             case DAY_OF_WEEK:
  1104.                 delta *= 24 * 60 * 60 * 1000; // 1 day
  1105.                 break;
  1106.  
  1107.             case HOUR_OF_DAY:
  1108.             case HOUR:
  1109.                 delta *= 60 * 60 * 1000; // 1 hour
  1110.                 break;
  1111.  
  1112.             case MINUTE:
  1113.                 delta *= 60 * 1000; // 1 minute
  1114.                 break;
  1115.  
  1116.             case SECOND:
  1117.                 delta *= 1000; // 1 second
  1118.                 break;
  1119.  
  1120.             case MILLISECOND:
  1121.                 // Simply break out on MILLISECOND
  1122.                 break;
  1123.  
  1124.             case ZONE_OFFSET:
  1125.             case DST_OFFSET:
  1126.             default:
  1127.                 throw new IllegalArgumentException();
  1128.             }
  1129.  
  1130.             setTimeInMillis(time + delta); // Automatically computes fields if necessary
  1131.  
  1132.             // Now do the DST adjustment alluded to above.
  1133.             // Only call setTimeInMillis if necessary, because it's an expensive call.
  1134.             dst -= internalGet(DST_OFFSET);
  1135.             if (delta != 0) setTimeInMillis(time + dst);
  1136.         }
  1137.     }
  1138.  
  1139.  
  1140.     /**
  1141.      * Overrides Calendar
  1142.      * Time Field Rolling function.
  1143.      * Rolls (up/down) a single unit of time on the given time field.
  1144.      * @param field the time field.
  1145.      * @param up Indicates if rolling up or rolling down the field value.
  1146.      * @exception IllegalArgumentException if an unknown field value is given.
  1147.      */
  1148.     public void roll(int field, boolean up)
  1149.     {
  1150.         roll(field, up ? +1 : -1);
  1151.     }
  1152.  
  1153.     /**
  1154.      * Roll a field by a signed amount.
  1155.      * Note: This will be made public later. [LIU]
  1156.      */
  1157.     void roll(int field, int amount)
  1158.     {
  1159.         if (amount == 0) return; // Nothing to do
  1160.  
  1161.         complete();
  1162.  
  1163.         int min = getMinimum(field);
  1164.         int max = getMaximum(field);
  1165.         int gap;
  1166.  
  1167.         switch (field) {
  1168.         case ERA:
  1169.         case YEAR:
  1170.         case AM_PM:
  1171.         case HOUR:
  1172.         case HOUR_OF_DAY:
  1173.         case MINUTE:
  1174.         case SECOND:
  1175.         case MILLISECOND:
  1176.             // These fields are handled simply, since they have fixed minima
  1177.             // and maxima.  The field DAY_OF_MONTH is almost as simple.  Other
  1178.             // fields are complicated, since the range within they must roll
  1179.             // varies depending on the date.
  1180.             break;
  1181.  
  1182.     case MONTH:
  1183.         // Rolling the month involves both pinning the final value to [0, 11]
  1184.         // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
  1185.         // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
  1186.         // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
  1187.         {
  1188.         int mon = (internalGet(MONTH) + amount) % 12;
  1189.         if (mon < 0) mon += 12;
  1190.         set(MONTH, mon);
  1191.  
  1192.         // Keep the day of month in range.  We don't want to spill over
  1193.         // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
  1194.         // mar3.
  1195.         // NOTE: We could optimize this later by checking for dom <= 28
  1196.         // first.  Do this if there appears to be a need. [LIU]
  1197.                 int monthLen = monthLength(mon, internalGet(YEAR));
  1198.         int dom = internalGet(DAY_OF_MONTH);
  1199.         if (dom > monthLen) set(DAY_OF_MONTH, monthLen);
  1200.         return;
  1201.         }
  1202.  
  1203.         case WEEK_OF_YEAR:
  1204.             {
  1205.                 // This follows the outline of WEEK_OF_MONTH, except it applies
  1206.                 // to the whole year.  Please see the comment for WEEK_OF_MONTH
  1207.                 // for general notes.
  1208.  
  1209.                 // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
  1210.                 // in this locale.  We have dow in 0..6.
  1211.                 int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  1212.                 if (dow < 0) dow += 7;
  1213.  
  1214.                 // Find the day of the week (normalized for locale) for the first
  1215.                 // of the year.
  1216.                 int fdy = (dow - internalGet(DAY_OF_YEAR) + 1) % 7;
  1217.                 if (fdy < 0) fdy += 7;
  1218.  
  1219.                 // Get the first day of the first full week of the year,
  1220.                 // including phantom days, if any.  Figure out if the first week
  1221.                 // counts or not; if it counts, then fill in phantom days.  If
  1222.                 // not, advance to the first real full week (skip the partial week).
  1223.                 int start;
  1224.                 if ((7 - fdy) < getMinimalDaysInFirstWeek())
  1225.                     start = 8 - fdy; // Skip the first partial week
  1226.                 else
  1227.                     start = 1 - fdy; // This may be zero or negative
  1228.  
  1229.                 // Get the day of the week (normalized for locale) for the last
  1230.                 // day of the year.
  1231.                 int yearLen = isLeapYear(internalGet(YEAR)) ? 366 : 365;
  1232.                 int ldy = (yearLen - internalGet(DAY_OF_YEAR) + dow) % 7;
  1233.                 // We know yearLen >= DAY_OF_YEAR so we skip the += 7 step here.
  1234.  
  1235.                 // Get the limit day for the blocked-off rectangular year; that
  1236.                 // is, the day which is one past the last day of the year,
  1237.                 // after the year has already been filled in with phantom days
  1238.                 // to fill out the last week.  This day has a normalized DOW of 0.
  1239.                 int limit = yearLen + 7 - ldy;
  1240.  
  1241.                 // Now roll between start and (limit - 1).
  1242.                 gap = limit - start;
  1243.                 int day_of_year = (internalGet(DAY_OF_YEAR) + amount*7 -
  1244.                                    start) % gap;
  1245.                 if (day_of_year < 0) day_of_year += gap;
  1246.                 day_of_year += start;
  1247.  
  1248.                 // Finally, pin to the real start and end of the month.
  1249.                 if (day_of_year < 1) day_of_year = 1;
  1250.                 if (day_of_year > yearLen) day_of_year = yearLen;
  1251.  
  1252.                 // Make sure that the year and day of year are attended to by
  1253.                 // clearing other fields which would normally take precedence.
  1254.                 // If the disambiguation algorithm is changed, this section will
  1255.                 // have to be updated as well.
  1256.                 set(DAY_OF_YEAR, day_of_year);
  1257.                 clear(MONTH);
  1258.                 return;
  1259.             }
  1260.         case WEEK_OF_MONTH:
  1261.             {
  1262.                 // This is tricky, because during the roll we may have to shift
  1263.                 // to a different day of the week.  For example:
  1264.  
  1265.                 //    s  m  t  w  r  f  s
  1266.                 //          1  2  3  4  5
  1267.                 //    6  7  8  9 10 11 12
  1268.  
  1269.                 // When rolling from the 6th or 7th back one week, we go to the
  1270.                 // 1st (assuming that the first partial week counts).  The same
  1271.                 // thing happens at the end of the month.
  1272.  
  1273.                 // The other tricky thing is that we have to figure out whether
  1274.                 // the first partial week actually counts or not, based on the
  1275.                 // minimal first days in the week.  And we have to use the
  1276.                 // correct first day of the week to delineate the week
  1277.                 // boundaries.
  1278.  
  1279.                 // Here's our algorithm.  First, we find the real boundaries of
  1280.                 // the month.  Then we discard the first partial week if it
  1281.                 // doesn't count in this locale.  Then we fill in the ends with
  1282.                 // phantom days, so that the first partial week and the last
  1283.                 // partial week are full weeks.  We then have a nice square
  1284.                 // block of weeks.  We do the usual rolling within this block,
  1285.                 // as is done elsewhere in this method.  If we wind up on one of
  1286.                 // the phantom days that we added, we recognize this and pin to
  1287.                 // the first or the last day of the month.  Easy, eh?
  1288.  
  1289.                 // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
  1290.                 // in this locale.  We have dow in 0..6.
  1291.                 int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  1292.                 if (dow < 0) dow += 7;
  1293.  
  1294.                 // Find the day of the week (normalized for locale) for the first
  1295.                 // of the month.
  1296.                 int fdm = (dow - internalGet(DAY_OF_MONTH) + 1) % 7;
  1297.                 if (fdm < 0) fdm += 7;
  1298.  
  1299.                 // Get the first day of the first full week of the month,
  1300.                 // including phantom days, if any.  Figure out if the first week
  1301.                 // counts or not; if it counts, then fill in phantom days.  If
  1302.                 // not, advance to the first real full week (skip the partial week).
  1303.                 int start;
  1304.                 if ((7 - fdm) < getMinimalDaysInFirstWeek())
  1305.                     start = 8 - fdm; // Skip the first partial week
  1306.                 else
  1307.                     start = 1 - fdm; // This may be zero or negative
  1308.  
  1309.                 // Get the day of the week (normalized for locale) for the last
  1310.                 // day of the month.
  1311.                 int monthLen = monthLength(internalGet(MONTH), internalGet(YEAR));
  1312.                 int ldm = (monthLen - internalGet(DAY_OF_MONTH) + dow) % 7;
  1313.                 // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.
  1314.  
  1315.                 // Get the limit day for the blocked-off rectangular month; that
  1316.                 // is, the day which is one past the last day of the month,
  1317.                 // after the month has already been filled in with phantom days
  1318.                 // to fill out the last week.  This day has a normalized DOW of 0.
  1319.                 int limit = monthLen + 7 - ldm;
  1320.  
  1321.                 // Now roll between start and (limit - 1).
  1322.                 gap = limit - start;
  1323.                 int day_of_month = (internalGet(DAY_OF_MONTH) + amount*7 -
  1324.                                     start) % gap;
  1325.                 if (day_of_month < 0) day_of_month += gap;
  1326.                 day_of_month += start;
  1327.  
  1328.                 // Finally, pin to the real start and end of the month.
  1329.                 if (day_of_month < 1) day_of_month = 1;
  1330.                 if (day_of_month > monthLen) day_of_month = monthLen;
  1331.  
  1332.                 // Set the DAY_OF_MONTH.  We rely on the fact that this field
  1333.                 // takes precedence over everything else (since all other fields
  1334.                 // are also set at this point).  If this fact changes (if the
  1335.                 // disambiguation algorithm changes) then we will have to unset
  1336.                 // the appropriate fields here so that DAY_OF_MONTH is attended
  1337.                 // to.
  1338.                 set(DAY_OF_MONTH, day_of_month);
  1339.                 return;
  1340.             }
  1341.         case DAY_OF_MONTH:
  1342.             max = monthLength(internalGet(MONTH), internalGet(YEAR));
  1343.             break;
  1344.         case DAY_OF_YEAR:
  1345.             {
  1346.                 // Roll the day of year using millis.  Compute the millis for
  1347.                 // the start of the year, and get the length of the year.
  1348.                 long delta = amount * ONE_DAY; // Scale up from days to millis
  1349.                 long min2 = time - (internalGet(DAY_OF_YEAR) - 1) * ONE_DAY;
  1350.                 int yearLength = isLeapYear(internalGet(YEAR)) ? 366 : 365;
  1351.                 time = (time + delta - min2) % (yearLength*ONE_DAY);
  1352.                 if (time < 0) time += yearLength*ONE_DAY;
  1353.                 setTimeInMillis(time + min2);
  1354.                 return;
  1355.             }
  1356.         case DAY_OF_WEEK:
  1357.             {
  1358.                 // Roll the day of week using millis.  Compute the millis for
  1359.                 // the start of the week, using the first day of week setting.
  1360.                 // Restrict the millis to [start, start+7days).
  1361.                 long delta = amount * ONE_DAY; // Scale up from days to millis
  1362.                 // Compute the number of days before the current day in this
  1363.                 // week.  This will be a value 0..6.
  1364.                 int leadDays = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  1365.                 if (leadDays < 0) leadDays += 7;
  1366.                 long min2 = time - leadDays * ONE_DAY;
  1367.                 time = (time + delta - min2) % ONE_WEEK;
  1368.                 if (time < 0) time += ONE_WEEK;
  1369.                 setTimeInMillis(time + min2);
  1370.                 return;
  1371.             }
  1372.         case DAY_OF_WEEK_IN_MONTH:
  1373.             {
  1374.                 // Roll the day of week in the month using millis.  Determine
  1375.                 // the first day of the week in the month, and then the last,
  1376.                 // and then roll within that range.
  1377.                 long delta = amount * ONE_WEEK; // Scale up from weeks to millis
  1378.                 // Find the number of same days of the week before this one
  1379.                 // in this month.
  1380.                 int preWeeks = (internalGet(DAY_OF_MONTH) - 1) / 7;
  1381.                 // Find the number of same days of the week after this one
  1382.                 // in this month.
  1383.                 int postWeeks = (monthLength(internalGet(MONTH), internalGet(YEAR)) -
  1384.                                  internalGet(DAY_OF_MONTH)) / 7;
  1385.                 // From these compute the min and gap millis for rolling.
  1386.                 long min2 = time - preWeeks * ONE_WEEK;
  1387.                 long gap2 = ONE_WEEK * (preWeeks + postWeeks + 1); // Must add 1!
  1388.                 // Roll within this range
  1389.                 time = (time + delta - min2) % gap2;
  1390.                 if (time < 0) time += gap2;
  1391.                 setTimeInMillis(time + min2);
  1392.                 return;
  1393.             }
  1394.         case ZONE_OFFSET:
  1395.         case DST_OFFSET:
  1396.         default:
  1397.             // These fields cannot be rolled
  1398.             throw new IllegalArgumentException();
  1399.         }
  1400.  
  1401.         // These are the standard roll instructions.  These work for all
  1402.         // simple cases, that is, cases in which the limits are fixed, such
  1403.         // as the hour, the month, and the era.
  1404.         gap = max - min + 1;
  1405.         int value = internalGet(field) + amount;
  1406.         value = (value - min) % gap;
  1407.         if (value < 0) value += gap;
  1408.         value += min;
  1409.  
  1410.         set(field, value);
  1411.     }
  1412.  
  1413.     /**
  1414.      * <pre>
  1415.      * Field names Minimum Greatest Minimum Least Maximum Maximum
  1416.      * ----------- ------- ---------------- ------------- -------
  1417.      * ERA 0 0 1 1
  1418.      * YEAR 1 1 5,000,000 5,000,000
  1419.      * MONTH 0 0 11 11
  1420.      * WEEK_OF_YEAR 0 0 53 54
  1421.      * WEEK_OF_MONTH 0 0 4 6
  1422.      * DAY_OF_MONTH 1 1 28 31
  1423.      * DAY_OF_YEAR 1 1 365 366
  1424.      * DAY_OF_WEEK 1 1 7 7
  1425.      * DAY_OF_WEEK_IN_MONTH -1 -1 4 6
  1426.      * AM_PM 0 0 1 1
  1427.      * HOUR 0 0 11 12
  1428.      * HOUR_OF_DAY 0 0 23 23
  1429.      * MINUTE 0 0 59 59
  1430.      * SECOND 0 0 59 59
  1431.      * MILLISECOND 0 0 999 999
  1432.      * ZONE_OFFSET -12*60*60*1000 -12*60*60*1000 12*60*60*1000 12*60*60*1000
  1433.      * DST_OFFSET 0 0 1*60*60*1000 1*60*60*1000
  1434.      * </pre>
  1435.      */
  1436.     private static final int MinValues[]
  1437.     = {0,1,0,0,0,1,1,1,-1,0,0,0,0,0,0,-12*60*60*1000,0};
  1438.     private static final int GreatestMinValues[]
  1439.     = {0,1,0,0,0,1,1,1,-1,0,0,0,0,0,0,-12*60*60*1000,0};// same as MinValues
  1440.     private static final int LeastMaxValues[]
  1441.     = {1,5000000,11,53,4,28,365,7,4,1,11,23,59,59,999,
  1442.        12*60*60*1000,1*60*60*1000};
  1443.     private static final int MaxValues[]
  1444.     = {1,5000000,11,54,6,31,366,7,6,1,12,23,59,59,999,
  1445.        12*60*60*1000,1*60*60*1000};
  1446.  
  1447.     /**
  1448.      * Returns minimum value for the given field.
  1449.      * e.g. for Gregorian DAY_OF_MONTH, 1
  1450.      * Please see Calendar.getMinimum for descriptions on parameters and
  1451.      * the return value.
  1452.      */
  1453.     public int getMinimum(int field)
  1454.     {
  1455.         return MinValues[field];
  1456.     }
  1457.  
  1458.     /**
  1459.      * Returns maximum value for the given field.
  1460.      * e.g. for Gregorian DAY_OF_MONTH, 31
  1461.      * Please see Calendar.getMaximum for descriptions on parameters and
  1462.      * the return value.
  1463.      */
  1464.     public int getMaximum(int field)
  1465.     {
  1466.         return MaxValues[field];
  1467.     }
  1468.  
  1469.     /**
  1470.      * Returns highest minimum value for the given field if varies.
  1471.      * Otherwise same as getMinimum(). For Gregorian, no difference.
  1472.      * Please see Calendar.getGreatestMinimum for descriptions on parameters
  1473.      * and the return value.
  1474.      */
  1475.     public int getGreatestMinimum(int field)
  1476.     {
  1477.         return GreatestMinValues[field];
  1478.     }
  1479.  
  1480.     /**
  1481.      * Returns lowest maximum value for the given field if varies.
  1482.      * Otherwise same as getMaximum(). For Gregorian DAY_OF_MONTH, 28
  1483.      * Please see Calendar.getLeastMaximum for descriptions on parameters and
  1484.      * the return value.
  1485.      */
  1486.     public int getLeastMaximum(int field)
  1487.     {
  1488.         return LeastMaxValues[field];
  1489.     }
  1490. }
  1491.